package bold.deposit.interception;


import bold.deposit.Account;
import bold.deposit.useful.CookieUtil;
import bold.deposit.useful.JWTUtil;
import bold.deposit.useful.Redis;
import bold.deposit.useful.Result;
import com.alibaba.fastjson.JSON;
import com.auth0.jwt.exceptions.SignatureVerificationException;
import com.auth0.jwt.exceptions.TokenExpiredException;
import lombok.extern.log4j.Log4j2;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;
import org.springframework.web.servlet.resource.DefaultServletHttpRequestHandler;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

@Log4j2
public class Authorize extends HandlerInterceptorAdapter {
    @Autowired
    private Redis redis;

    /**
     * 使用此方法时
     * 方法，类 不能有NoAuthorize 注解
     */
    public static Account get(HttpServletRequest request) {
        return (Account) request.getAttribute("Authorize");
    }

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws IOException {
        //todo 过滤所有静态资源 防止新增文件夹
        if (request.getRequestURI().contains(".")) {
            return true;
        }

        if (handler instanceof HandlerMethod) {
            HandlerMethod method = (HandlerMethod) handler;
            NoAuthorize classNote = method.getBeanType().getAnnotation(NoAuthorize.class);

            if (classNote != null) {
                return true;
            }

            NoAuthorize auth = method.getMethodAnnotation(NoAuthorize.class);
            if (auth != null) {
                return true;
            }
        } else if (handler instanceof DefaultServletHttpRequestHandler) {
            //todo 没有映射 进入默认处理器
            throw new NoMapping();
        }


        String token = CookieUtil.get(request, "token");
        if (token == null) {
            throw new NotLogin();
        }

        //jwt 校验 登录是否有效
        Account account;
        try {
            account = JWTUtil.get(token, Account.class);
        } catch (TokenExpiredException e) {
            throw new LoginInvalidity();
        } catch (SignatureVerificationException e) {
            throw new NotLogin();
        }

        //单点登录 再次判断
        String loginInfo = redis.get(token);
        if (loginInfo == null) {
            //2、登录失效
            String requestType = request.getHeader("X-Requested-With");
            if ("XMLHttpRequest".equals(requestType)) {
                response.setContentType("text/html;charset=UTF-8");
                response.getWriter().print(JSON.toJSON(new Result(402)));
                response.getWriter().close();
                return false;
            }
            throw new LoginInvalidity();
        }
        request.setAttribute("Authorize", account);//todo 存入request
        return true;
    }

    class NotLogin extends RuntimeException {
        private static final long serialVersionUID = -2308276871291114916L;
    }

    class LoginInvalidity extends RuntimeException {
        private static final long serialVersionUID = -6906272804600934414L;
    }

    class NoMapping extends RuntimeException {
        private static final long serialVersionUID = -6906272804600934414L;
    }

}
